import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

/**
 * 针对ExecutorService线程池理解
 *
 * 1. Executor接口：执行提交的任务(线程)，只有一个方法 execute(Runnable a)
 * 2. ExecutorService(继承自Executor)接口：提供了一些异步的多线程操作方法，如execute(), submit(), shutdown(), shutdownNow()等
 * 3. Executors类： 提供了一些工厂方法和一些公共方法来操作Executor子类和ThreadFactory等，如newXXX()，xxxThreadFactory()等
 * 4. Futrue接口：代表了线程执行结果，提供了获取线程执行结果和取消线程的方法，如get()，cancle()等
 * 5. Callable接口：JDK1.5提供的有返回值的线程执行新接口
 */
public class Demo01ThreadPool {
    public static void main(String[] args) {
/**
 * Executors.newSingleThreadExecutor() 创建容量唯一的线程缓存池，只会有一个线程
 * Executors.newCachedThreadPool()     创建一个可缓存线程池，若60s中线程没有被使用，则会停止线程并从缓存池中移除(推举使用)
 * Executors.newFixedThreadPool(5)     创建一个可重用固定线程数的线程池
 *
 * Executors.newScheduledThreadPool(2) 创建一个定长线程池，支持定时及周期性任务执行
 *      schedule(Runnable command,long delay, TimeUnit unit) 表示从提交任务开始计时，多长时间后执行
 *      scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnitunit)  也就是将在 initialDelay 后开始执行，然后在initialDelay+period 后执行，接着在 initialDelay + 2 * period 后执行，依此类推
 *      scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) 创建并执行一个在给定初始延迟后首次启用的定期操作，随后，在每一次执行终止和下一次执行开始之间都存在给定的延迟
 */
         int count = 3;
        ExecutorService executorService = Executors.newFixedThreadPool(count);
        List<Future> resultList = new LinkedList<>();
        /**
         *  ExecutorService提供的execute()方法和submit()方法的区别:
         *
         *      execute()方法只接受Runnable类型的实例，所以不能拿到返回值
         *      submit ()方法接受Runnable和Callable实例，会返回Future实例，
         *          Runnable任务没有返回值future.get()为null，而Callable任务有返回值
         */
        resultList.add(executorService.submit(new Task1()));
        resultList.add(executorService.submit(new Task1()));
        resultList.add(executorService.submit(new LongTask()));
        resultList.add(executorService.submit(new Task1()));

        //shutdown()销毁线程池
        executorService.shutdown();     //停止接收新任务,等待已经提交的任务执行完成,(生命周期方法1)
//        List<Runnable> runnables = executorService.shutdownNow();//这个方法会强制关闭，它将取消所有运行中的任务和在工作队列中等待的任务,返回等待执行的任务(生命周期方法2)
//        System.out.println("等待没有被执行的任务数:"+runnables.size()+"");

        try {
            /**
             *(生命周期方法1)
             *awaitTermination()方法,这个方法会使线程等待timeout时长，当超过timeout时间后，
             *     会监测ExecutorService的所有任务是否已经执行完成，若关闭则返回true，否则返回false。一般情况下会和shutdown方法组合使用
             */
            while (!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
                System.out.println( "线程池没有关闭");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

//        /**
//         *(生命周期方法1)
//         * isTerminated方法：这个方法会校验ExecutorService当前的状态是否为“TERMINATED”即关闭状态,如果是为true否则返回flase
//         * isShutDown方法:  当调用shutdown()方法后返回为true。而isTerminated方法是所以任务完成后返回true;
//         */
//        System.out.println("开始" + System.currentTimeMillis());
//        while (!executorService.isTerminated()) {
//        }
//        System.out.println("结束" + System.currentTimeMillis());

        System.out.println( "线程池关闭" + Thread.currentThread().getName());
        for (Future future : resultList) {
            try {
                System.out.println( "future.get():" + future.get() + "线程" + Thread.currentThread().getName());

            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 随机生成10个字符的字符串的任务
 * Callable接口和Runable接口最大的区别是Callable可以拥有返回值，
 * 并可以通过回调的方式获取。同时通过Future的get方法，可以同步的获取到返回值，并保证任务已经完成
 */
class Task1 implements Callable<String> {

    @Override
    public String call() throws Exception {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 10; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        System.out.println( sb.toString() + "当前线程:" + Thread.currentThread().getName());
        return sb.toString();
    }

}

/**
 * 长时间的任务
 */
class LongTask implements Callable<String> {

    @Override
    public String call() throws Exception {
        TimeUnit.SECONDS.sleep(10);
        System.out.println( "success" + "当前线程:" + Thread.currentThread().getName());
        return "success";
    }

}
